import random
from typing import List, Tuple

from gmpy2 import powmod, mpz, gcd
from mpmath import difference

import threshold_paillier
from threshold_paillier import add_homomorphically, \
    subtract_homomorphically, multiply_homomorphically, PublicKey
from threshold_paillier import encrypt
from threshold_paillier import key_gen
from threshold_paillier import rerandomize
from threshold_paillier import partial_decrypt
from threshold_paillier import combine_partial_decrypt
from sympy import isprime


def generate_random_prime(upper_bound):
    """
    生成一个小于 upper_bound 的随机素数。
    使用 sympy 的 isprime 方法进行素性测试。
    """
    while True:
        # 生成一个随机奇数
        num = random.randint(2, upper_bound - 1)
        if num % 2 == 0:
            num += 1  # 保证是奇数，偶数除 2 以外都不是素数
        # 判断是否为素数
        if isprime(num):
            return num
# 生成小于 upper_bound  的随机素数


#随机值的选择 会影响结果的输出， 原因是 随机数与密文相乘 如果超过n*n  会导致错误结果
'''def generate_random_number(n, down_bound, up_bound):
    return random.randint(down_bound, up_bound - 1) % n**2'''
'''def generate_random_number(n):
    return powmod(mpz(random.randint(1, n - 1)), n, n ** 2)'''
def generate_random_number(n, down_bound, up_bound):
    """
    生成一个在 down_bound 和 up_bound 之间的随机数，并确保它与 n 互质。
    """
    while True:
        # 生成随机数
        ret = random.randint(down_bound, up_bound)
        if gcd(ret, n) == 1:
            return mpz(ret)

# x0 > x1 输出1
# x0 < x1 输出0
def secure_comparison_protocol(Enc_1, Enc_2, threshold_l, parties_t, keys):

    # 从 keys 中提取 public_key 和 private_keys
    public_key = keys.public_key
    private_keys = keys.private_keys
    n = public_key.n

    # 生成域Z_p 中的素数p
    upper_bound = 100
    random_prime = generate_random_prime(upper_bound)

    # 1. 随机生成 r1 和 r2
    r1 = generate_random_number(n, 1, upper_bound)  # n 是随机数范围的最大值
    r2 = generate_random_number(n, 1, r1)  # 使得 r2 总是小于 r1
    #r1 = generate_random_number(n, 1, n * n - 1)  # n*n 范围内的随机数
    #r2 = generate_random_number(n, 1, r1)  # 使得 r2 总是小于 r1
    #r1=2
    #r2=1

    # 2. Party P1 计算 Enc(c) = Enc( r1(x_0 - x_1) - r2 )
    difference = subtract_homomorphically(Enc_1, Enc_2, public_key)  # 同态减法 (x_0 - x_1)
    #no problem  r1*(X0-X1)=0
    #r1 * (x_0 - x_1) - r2
    res = subtract_homomorphically(
        multiply_homomorphically(difference, r1, public_key),  # r1 * (x_0 - x_1)
        encrypt(r2, public_key),  # 加密 r2   减去 r2  ----> r1 * (x_0 - x_1) - r2
        public_key
    )
    # 3. a1 = Enc(0), a2 = Enc(1), a3 = Enc(res)
    a1 = encrypt(1, public_key)
    a2 = encrypt(0, public_key)

    # 4. 进行 re-randomizing 和 permuting
    for i in range(threshold_l):
        # 掷硬币 b_i 为0或1
        b_i = random.randint(0, 1)
        # 随机交换 a1 和 a2
        if b_i:
            a1, a2 = a2, a1

        # 重新随机化 a1 和 a2
        a1 = rerandomize(a1, public_key)
        a2 = rerandomize(a2, public_key)

        # 随机生成新的 r1 和 r2
        r1 = generate_random_number(n, 1, upper_bound)
        r2 = generate_random_number(n, 1, r1)
        #r1 = generate_random_number(n, 1, n * n - 1)  # 在每次迭代时都生成新的随机数
        #r2 = generate_random_number(n, 1, r1)
        #r1=2
        #r2=1

        # 更新加密结果 a3
        res = multiply_homomorphically(res, (-2 * b_i + 1) * r1, public_key)
        #res = add_homomorphically(res, encrypt((2 * b_i - 1) * r2, public_key), public_key)
        res = subtract_homomorphically(res, encrypt((2 * b_i - 1) * r2, public_key), public_key)
    # 5. 解密并返回结果
    decryption_shares = []
    for i in range(parties_t):
        decryption_shares.append((mpz(i + 1), partial_decrypt(res, public_key, private_keys[i])))
    # 6. 合并部分解密结果并判断返回 a1 或 a2
    decrypted_result = combine_partial_decrypt(decryption_shares, public_key)
    # 判断解密结果
    if decrypted_result < 0: # x0 <= x1
        return a1
    else:
        return a2


def test_secure_comparison_protocol():

    # 1. 定义密钥生成的参数
    n = 1024  # 加密密钥的位长度
    threshold_l = 2  # 阈值
    parties_t = 3  # 总参与方数

    # 2. 生成密钥
    keys = threshold_paillier.key_gen(key_length=n, threshold_l=threshold_l, parties_t=parties_t)

    # 3. 假设我们有两个加密的数字，分别是 Enc(x0) 和 Enc(x1)
    x0 = 6
    x1 = 5

    # 4. 对 x0 和 x1 进行加密
    Enc_x0 = encrypt(x0, keys.public_key)
    Enc_x1 = encrypt(x1, keys.public_key)

    # 5. 调用安全比较协议
    # 返回结果为
    # E(1) : x0 <= x1
    # E(0) : x0 > x1
    result = secure_comparison_protocol(Enc_x0, Enc_x1, threshold_l, parties_t, keys)

    # 6. 输出结果
    print("The comparison result is:")
    decryption_shares = []
    for i in range(parties_t):
        decryption_shares.append((mpz(i + 1), partial_decrypt(result, keys.public_key, keys.private_keys[i])))
    decrypted_result = combine_partial_decrypt(decryption_shares, keys.public_key)
    print(f" x0,x1 = {x0,x1}")
    #print(f"decrypted_result = {decrypted_result}")
    if decrypted_result == 0:  # 如果解密结果是 0
        print("x0 is greater than or equal to x1")
        print("x0 > x1")
    elif decrypted_result == 1:  # 如果解密结果是 1
        print("x0 is less than x1")
        print("x0 <= x1")
    else:
        print("Unexpected result")

# 运行测试用例
#test_secure_comparison_protocol()
